import Vue from "vue"
import Clipboard from "clipboard"

export const storage = {
  // 封装操作localstorage本地存储的方法
  // 存储
  set(key, value) {
    localStorage.setItem(key, JSON.stringify(value))
  },
  // 取出数据
  get(key) {
    return JSON.parse(localStorage.getItem(key))
  },
  // 删除数据
  remove(key) {
    localStorage.removeItem(key)
  },
  // 清除所有存储
  clear() {
    localStorage.clear()
  }
}

// 时间格式转换函数
// 参数:
// data: 毫秒时间戳
// fmt:需要的格式（连接字符可自定义）
// 例:
// formatDate(1566268629000, 'yyyy-MM-dd hh:mm:ss'); //2019-08-20 10:37:09
// formatDate(1566268629000, 'yyyy-MM-dd hh:mm'); //2019-08-20 10:37
// formatDate(1566268629000, 'yyyy-MM-dd hh'); //2019-08-20 10
// formatDate(1566268629000, 'yyyy-MM-dd'); //2019-08-20
// formatDate(1566268629000, 'yyyy-MM'); //2019-08
// formatDate(1566268629000, 'yyyy'); //2019
function padLeftZero(str) {
  return `00${str}`.substr(str.length)
}

export function formatDate(date, fmt1) {
  const oDate = new Date(parseInt(date))
  const o = {
    "M+": oDate.getMonth() + 1, // 月份
    "d+": oDate.getDate(), // 日
    "h+": oDate.getHours(), // 小时
    "m+": oDate.getMinutes(), // 分
    "s+": oDate.getSeconds(), // 秒
    "q+": Math.floor((oDate.getMonth() + 3) / 3), // 季度
    S: oDate.getMilliseconds() // 毫秒
  }
  let fmt = fmt1

  if (/(y+)/.test(fmt)) { // 年份
    fmt = fmt.replace(RegExp.$1, `${oDate.getFullYear()}`.substr(4 - RegExp.$1.length))
  }
  Object.keys(o).forEach((k) => {
    if (new RegExp(`(${k})`).test(fmt)) {
      const str = `${o[k]}`

      fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : padLeftZero(str))
    }
  })

  return fmt
}

// 文本复制
function copySuccess() {
  Vue.prototype.$message({
    type: "success",
    message: "复制文本成功",
    duration: 1500
  })
}

function copyFail() {
  Vue.prototype.$message({
    message: "该浏览器不支持自动复制",
    type: "warning"
  })
}

export function copyText(text, e) {
  const clipboard = new Clipboard(e.target, {
    text: () => text
  })
  clipboard.on("success", () => {
    copySuccess()
    // 释放内存
    clipboard.destroy()
  })
  clipboard.on("error", () => {
    // 不支持复制
    copyFail()
    // 释放内存
    clipboard.destroy()
  })
  // 解决第一次点击不生效的问题，如果没有，第一次点击会不生效
  clipboard.onClick(e)
}

/**
 * @param {string} str 首字母转大写
 * @returns {string}
 */
export function firstUpperCase(str) {
  return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase());
}

/**
 * @param {string} path
 * @returns {Object}
 */
export function getQueryObject(path) {
  const url = path == null ? window.location.href : path
  const search = url.substring(url.lastIndexOf("?") + 1)
  const obj = {}
  const reg = /([^?&=]+)=([^?&=]*)/g

  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1)

    let val = decodeURIComponent($2)

    val = String(val)
    obj[name] = val
    return rs
  })
  return obj
}

/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual) {
  const newArray = []

  for (let i = 0; i < actual.length; i += 1) {
    if (actual[i]) {
      newArray.push(actual[i])
    }
  }
  return newArray
}

/**
 * 对象转url参数
 * @param {Object} json
 * @returns {Array}
 */
export function param(json) {
  if (!json) {
    return ""
  }
  return cleanArray(
    Object.keys(json).map((key) => {
      if (json[key] === undefined) {
        return ""
      }
      return `${encodeURIComponent(key)}=${encodeURIComponent(json[key])}`
    })
  ).join("&")
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
  const search = url.split("?")[1]

  if (!search) {
    return {}
  }
  return JSON.parse(
    `{"${
      decodeURIComponent(search)
        .replace(/"/g, "\\\"")
        .replace(/&/g, "\",\"")
        .replace(/[=]/g, "\":\"")
        .replace(/\+/g, " ")
    }"}`
  )
}

/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val) {
  const div = document.createElement("div")

  div.innerHTML = val
  return div.textContent || div.innerText
}

/**
 * 合并两个对象，赋予最后一个对象优先权
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(targetObj, source) {
  let target = targetObj
  if (typeof target !== "object") {
    target = {}
  }
  if (Array.isArray(source)) {
    return source.slice()
  }
  Object.keys(source).forEach((property) => {
    const sourceProperty = source[property]

    if (typeof sourceProperty === "object") {
      target[property] = objectMerge(target[property], sourceProperty)
    } else {
      target[property] = sourceProperty
    }
  })
  return target
}

/**
 * @param {string} type
 * @returns {Date}
 */
export function getTime(type) {
  if (type === "start") {
    return new Date().getTime() - 3600 * 1000 * 24 * 90
  }
  return new Date(new Date().toDateString())
}

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func, wait, immediate) {
  let timeout

  let args1

  let context

  let timestamp

  let
    result

  const later = function () {
    // 据上一次触发时间间隔
    const last = Number(new Date()) - timestamp

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args1)
        if (!timeout) {
          args1 = null
          context = null
        }
      }
    }
  }

  return function (...args) {
    context = this
    timestamp = Number(new Date())
    const callNow = immediate && !timeout
    // 如果延时不存在，重新设定延时

    if (!timeout) {
      timeout = setTimeout(later, wait)
    }

    if (callNow) {
      result = func.apply(context, args)
      args = null
      context = null
    }

    return result
  }
}

/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source) {
  if (!source && typeof source !== "object") {
    throw new Error("error arguments", "deepClone")
  }
  const targetObj = source.constructor === Array ? [] : {}

  Object.keys(source).forEach((keys) => {
    if (source[keys] && typeof source[keys] === "object") {
      targetObj[keys] = deepClone(source[keys])
    } else {
      targetObj[keys] = source[keys]
    }
  })
  return targetObj
}

/**
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr) {
  return Array.from(new Set(arr))
}

/**
 * 树状数据转扁平数据
 * @param {array} tree 树状数据
 * @param {string} childrenKey 子项的key名 比如：children之类的
 * @return {array} 返回扁平数据
 */
export function treeToJsonArray(tree, childrenKey) {
  let queen = [...tree]
  const result = []
  while (queen.length) {
    const first = queen.shift()
    if (first[childrenKey].length > 0) {
      queen = queen.concat(first[childrenKey])
      first[childrenKey] = true
    }
    result.push(first)
  }
  return result
}

/**
 * 扁平数据转树状数据
 * @param {array} arr 扁平数据
 * @param {string} idKey
 * @param {string} parentKey
 * @param {string} childrenKey
 * @return {array} 返回树状数据
 */
export function jsonArrayToTree(arr, idKey, parentKey, childrenKey) {
  const list = JSON.parse(JSON.stringify(arr))
  const hash = {}
  const r = []
  for (let i = 0; i < list.length; i += 1) {
    hash[list[i][idKey]] = list[i]
  }
  for (let i = 0; i < list.length; i += 1) {
    const item = list[i]
    const itemParent = hash[item[parentKey]]
    if (itemParent) {
      if (!itemParent[childrenKey]) {
        itemParent[childrenKey] = []
      }
      itemParent[childrenKey].push(item)
    } else {
      r.push(item)
    }
  }
  return r
}

/**
 * @returns {string}
 */
export function createUniqueString() {
  const timestamp = `${Number(new Date())}`
  const randomNum = `${parseInt((1 + Math.random()) * 65536, 0)}`
  return Number(randomNum + timestamp).toString(32)
}

/**
 * 获取与JSON中某些键和值匹配的对象的示例
 * 通过key或者val拿到树状数据对应那级的数据
 * @param {array,object} obj
 * @param {string} key
 * @param {string,number} val
 * @return {array} 返回key和val对应那级的数据
 *  return an array of objects according to key, value, or key and value matching
 */
export function getObjects(obj, key, val) {
  let objects = []
  Object.key(obj).forEach((i) => {
    if (Object.prototype.hasOwnProperty.call(obj, i)) {
      if (typeof obj[i] == "object") {
        objects = objects.concat(getObjects(obj[i], key, val))
      } else
      // if key matches and value matches or if key matches and value is not passed (eliminating the case where key matches but passed value does not)
      if (i == key && obj[i] == val || i == key && val == "") { //
        objects.push(obj)
      } else if (obj[i] == val && key == "") {
        // only add if the object is not already in the array
        if (objects.lastIndexOf(obj) == -1) {
          objects.push(obj)
        }
      }
    }
  })
  return objects
}

// var json = '{"glossary":{"title":"example glossary","GlossDiv":{"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","ID":"44","str":"SGML","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}}}}';
//
// var jsonData = JSON.parse(json);
//
// console.log("初始数据",jsonData)
// example of grabbing objects that match some key and value in JSON
// 通过传入key和值拿到当前树位置的那级数据
// console.log(getObjects(jsonData,'ID','SGML'));
// returns 1 object where a key names ID has the value SGML

// var s=getObjects(jsonData,'ID','SGML');
// s[0].GlossTerm="撒旦教告诉"
// console.log(jsonData)
// 修改jsonData会影响到s

// example of grabbing objects that match some key in JSON
// console.log(getObjects(jsonData,'ID',''));
// returns 2 objects since keys with name ID are found in 2 objects

// example of grabbing obejcts that match some value in JSON
// console.log(getObjects(jsonData,'','SGML'));
// returns 2 object since 2 obects have keys with the value SGML

// example of grabbing objects that match some key in JSON
// console.log(getObjects(jsonData,'ID',''));
// returns 2 objects since keys with name ID are found in 2 objects

/**
 * 树状数据返回与某个键（key）匹配的值数组
 * @param {array,object} obj
 * @param {string} key
 * @return {array} 返回数组
 *  return an array of values that match on a certain key
 *  示例: 从JSON中传递的任何键获取值的示例
 *  console.log(getValues(jsonData,'ID'));
 *  returns array ["SGML", "44"]
 */
export function getValues(obj, key) {
  let objects = []
  Object.key(obj).forEach((i) => {
    if (Object.prototype.hasOwnProperty.call(obj, i)) {
      if (typeof obj[i] == "object") {
        objects = objects.concat(getValues(obj[i], key))
      } else if (i == key) {
        objects.push(obj[i])
      }
    }
  })
  return objects
}

/**
 * 树状数据返回与某个值匹配的键数组
 * @param {array,object} obj
 * @param {string,number} val
 * @return {array} 返回数组
 *  return an array of keys that match on a certain value
 *  //示例:通过JSON中的值搜索获取键的示例
 * // console.log(getKeys(jsonData,'SGML'));
 * //returns array ["ID", "SortAs", "Acronym", "str"]
 */
export function getKeys(obj, val) {
  let objects = []
  Object.key(obj).forEach((i) => {
    if (!Object.prototype.hasOwnProperty.call(obj, i)) {
      if (typeof obj[i] == "object") {
        objects = objects.concat(getKeys(obj[i], val))
      } else if (obj[i] == val) {
        objects.push(i)
      }
    }
  })
  return objects
}

/**
 * 十六进制颜色转为RGB
 * @param {string} sColor 16进制的值
 * @param {string} change
 * @return {string} rgb
 *
 */
export function colorRgb(sColor, change) {
  sColor = sColor.toLowerCase();
  // 十六进制颜色值的正则表达式
  const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
  // 如果是16进制颜色
  if (sColor && reg.test(sColor)) {
    if (sColor.length === 4) {
      let sColorNew = "#";
      for (let i = 1; i < 4; i += 1) {
        sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
      }
      sColor = sColorNew;
    }
    // 处理六位的颜色值
    const sColorChange = [];
    for (let i = 1; i < 7; i += 2) {
      sColorChange.push(parseInt(`0x${sColor.slice(i, i + 2)}`, 0));
    }
    if (change === "des") {
      sColorChange[0] += 20;
      sColorChange[1] += 15;
      sColorChange[2] += 10;
    }
    return `rgb(${sColorChange.join(",")})`;
  }
  return sColor;
}
